home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / fscheck / save < prev    next >
Encoding:
Text File  |  1989-10-04  |  29.8 KB  |  1,168 lines

  1. /* 
  2.  * fsUtils.c --
  3.  *
  4.  *    Utility procedures for fscheck
  5.  *
  6.  * Copyright 1989 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /a/newcmds/fscheck/RCS/fsUtils.c,v 1.3 89/09/25 16:41:21 jhh Exp Locker: jhh $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include "option.h"
  21. #include "list.h"
  22. #include "diskUtils.h"
  23. #include "fscheck.h"
  24. #include <string.h>
  25. #include <host.h>
  26. #include <sys/file.h>
  27. #include <sys/stat.h>
  28. #include <stdio.h>
  29.  
  30. void WriteOutputFile();
  31. int CloseOutputFile();
  32.  
  33. FILE outputFileInfo;
  34. FILE *outputFile = &outputFileInfo;
  35.  
  36.  
  37. /*
  38.  *----------------------------------------------------------------------
  39.  *
  40.  * ReadDomainHeader --
  41.  *
  42.  *    Read the domain header off the disk.
  43.  *
  44.  * Results:
  45.  *    None.
  46.  *
  47.  * Side effects:
  48.  *    Fill in the domain header.
  49.  *
  50.  *----------------------------------------------------------------------
  51.  */
  52. void
  53. ReadDomainHeader(partFID, diskInfoPtr, domainPtr)
  54.     int            partFID;    /* Handle on raw disk */
  55.     Disk_Info        *diskInfoPtr;    /* Information from the super block */
  56.     Fsdm_DomainHeader    *domainPtr;    /* Reference to domain header to
  57.                      * fill in */
  58. {
  59.     if (Disk_SectorRead(partFID, diskInfoPtr->domainSector,
  60.            diskInfoPtr->numDomainSectors, (Address)domainPtr) < 0) {
  61.     OutputPerror("ReadDomainHeader: Read failed");
  62.     exit(EXIT_READ_FAILURE);
  63.     }
  64. }
  65.  
  66.  
  67. /*
  68.  *----------------------------------------------------------------------
  69.  *
  70.  * WriteDomainHeader --
  71.  *
  72.  *    Read the domain header off the disk.
  73.  *
  74.  * Results:
  75.  *    None.
  76.  *
  77.  * Side effects:
  78.  *    Fill in the domain header.
  79.  *
  80.  *----------------------------------------------------------------------
  81.  */
  82. void
  83. WriteDomainHeader(partFID, diskInfoPtr, domainPtr)
  84.     int            partFID;    /* Handle on raw disk */
  85.     Disk_Info        *diskInfoPtr;    /* Information from the super block */
  86.     Fsdm_DomainHeader    *domainPtr;    /* Reference to domain header to
  87.                      * fill in */
  88. {
  89.     if (Disk_SectorWrite(partFID, diskInfoPtr->domainSector,
  90.             diskInfoPtr->numDomainSectors, (Address)domainPtr) < 0) {
  91.     OutputPerror("WriteDomainHeader: Write failed");
  92.     exit(EXIT_WRITE_FAILURE);
  93.     }
  94. }
  95.  
  96.  
  97. /*
  98.  *----------------------------------------------------------------------
  99.  *
  100. * ReadFileDescBitmap --
  101.  *
  102.  *    Read in the file descriptor bitmap.
  103.  *
  104.  * Results:
  105.  *    A pointer to the file descriptor bit map.
  106.  *
  107.  * Side effects:
  108.  *    Memory allocated for the bit map.
  109.  *
  110.  *----------------------------------------------------------------------
  111.  */
  112. unsigned char *
  113. ReadFileDescBitmap(partFID, domainPtr)
  114.     register Fsdm_DomainHeader *domainPtr;    /* Ptr to domain to read bitmap for. */
  115. {
  116.     register unsigned char *bitmap;
  117.  
  118.     /*
  119.      * Allocate the bitmap.
  120.      */
  121.     AllocByte(bitmap,unsigned char,domainPtr->fdBitmapBlocks * FS_BLOCK_SIZE);
  122.     if (tooBig) {
  123.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  124.     exit(EXIT_MORE_MEMORY);
  125.     }
  126.     if (Disk_BlockRead(partFID, domainPtr, domainPtr->fdBitmapOffset,
  127.           domainPtr->fdBitmapBlocks, (Address)bitmap) < 0) {
  128.     OutputPerror("ReadFileDescBitmap: Read failed");
  129.     exit(EXIT_READ_FAILURE);
  130.     }
  131.     return(bitmap);
  132. }
  133.  
  134.  
  135. /*
  136.  *----------------------------------------------------------------------
  137.  *
  138.  * WriteFileDescBitmap --
  139.  *
  140.  *    Write out the file descriptor bitmap.
  141.  *
  142.  * Results:
  143.  *    None.
  144.  *
  145.  * Side effects:
  146.  *    None.
  147.  *
  148.  *----------------------------------------------------------------------
  149.  */
  150. void
  151. WriteFileDescBitmap(partFID, domainPtr, bitmap)
  152.     int                partFID;    /* Raw handle on disk. */
  153.     register Fsdm_DomainHeader     *domainPtr;    /* Domain to write bitmap for.*/
  154.     register unsigned char     *bitmap;    /* Bitmap to write. */
  155. {
  156.     if (Disk_BlockWrite(partFID, domainPtr, domainPtr->fdBitmapOffset,
  157.            domainPtr->fdBitmapBlocks, (Address)bitmap) < 0) {
  158.     OutputPerror("WriteFileDescBitmap: Write failed");
  159.     exit(EXIT_WRITE_FAILURE);
  160.     }
  161. }
  162.  
  163.  
  164. /*
  165.  *----------------------------------------------------------------------
  166.  *
  167.  * ReadBitmap --
  168.  *
  169.  *    Read the bitmap off disk.
  170.  *
  171.  * Results:
  172.  *    A pointer to the bitmap.
  173.  *
  174.  * Side effects:
  175.  *    Memory allocated for the bit map.
  176.  *
  177.  *----------------------------------------------------------------------
  178.  */
  179. unsigned char *
  180. ReadBitmap(partFID, domainPtr)
  181.     int                partFID;    /* Raw disk handle. */
  182.     register Fsdm_DomainHeader    *domainPtr;    /* Domain to read. */
  183. {
  184.     unsigned char *bitmap;
  185.     AllocByte(bitmap,unsigned char,domainPtr->bitmapBlocks * FS_BLOCK_SIZE);
  186.     if (tooBig) {
  187.     Output(stderr,"CheckFileSystem: Heap limit too small.\n");
  188.     exit(EXIT_MORE_MEMORY);
  189.     }
  190.     if (Disk_BlockRead(partFID, domainPtr, domainPtr->bitmapOffset,
  191.           domainPtr->bitmapBlocks, (Address) bitmap) < 0) {
  192.     OutputPerror("ReadBitmap: Read failed");
  193.     exit(EXIT_READ_FAILURE);
  194.     }
  195.     return(bitmap);
  196. }
  197.  
  198.  
  199. /*
  200.  *----------------------------------------------------------------------
  201.  *
  202.  * WriteBitmap --
  203.  *
  204.  *    Write the bitmap to disk.
  205.  *
  206.  * Results:
  207.  *    None.
  208.  *
  209.  * Side effects:
  210.  *    None.
  211.  *
  212.  *----------------------------------------------------------------------
  213.  */
  214. void
  215. WriteBitmap(partFID, domainPtr, bitmap)
  216.     int                partFID;    /* Raw handle for disk. */
  217.     register Fsdm_DomainHeader    *domainPtr;    /* Domain to write. */
  218.     unsigned char        *bitmap;    /* Bitmap to write. */
  219. {
  220.     if (Disk_BlockWrite(partFID, domainPtr, domainPtr->bitmapOffset,
  221.            domainPtr->bitmapBlocks, (Address) bitmap) < 0) {
  222.     OutputPerror("WriteBitmap: Write failed");
  223.     exit(EXIT_WRITE_FAILURE);
  224.     }
  225. }
  226.  
  227.  
  228. /*
  229.  *----------------------------------------------------------------------
  230.  *
  231.  * WriteFileDesc --
  232.  *
  233.  *    Write the file descriptors to disk.
  234.  *
  235.  * Results:
  236.  *    None.
  237.  *
  238.  * Side effects:
  239.  *    File descriptors on the modified list are all written to disk.
  240.  *
  241.  *----------------------------------------------------------------------
  242.  */
  243. void
  244. WriteFileDesc(partFID, domainPtr, listPtr, descInfoPtr)
  245.     int             partFID;    /* Raw handle for disk. */
  246.     register Fsdm_DomainHeader     *domainPtr;    /* Domain to write to. */
  247.     List_Links            *listPtr;    /* Pointer to list of modified
  248.                          * file descriptors to write
  249.                          * out. */
  250.     FdInfo            *descInfoPtr;    /* Pointer to info about all
  251.                          * of the descriptors. */
  252.                     
  253. {
  254.     char        block[FS_BLOCK_SIZE];
  255.     int            blockNum;
  256.     int            offset;
  257.     ModListElement    *modElemPtr;
  258.     int            badBlock;
  259.  
  260.     LIST_FORALL(listPtr, (List_Links *)modElemPtr) {
  261.     badBlock = 0;
  262.     blockNum = domainPtr->fileDescOffset + 
  263.             modElemPtr->fdNum / FSDM_FILE_DESC_PER_BLOCK;
  264.     offset = (modElemPtr->fdNum & (FSDM_FILE_DESC_PER_BLOCK - 1)) *
  265.             FSDM_MAX_FILE_DESC_SIZE;
  266.     /*
  267.      * Try to read the whole block at once unless we already know it's
  268.      * bad.  Read it a sector at a time if we hit an error earlier
  269.      * or if we get one now.
  270.      */
  271.     if ((descInfoPtr[modElemPtr->fdNum].flags &
  272.          (FD_RELOCATE|FD_UNREADABLE)) == 0) {
  273.         if (Disk_BlockRead(partFID, domainPtr, blockNum, 1,
  274.                    (Address) block) < 0) {
  275.         OutputPerror("WriteFileDesc: Warning: read failed");
  276.         badBlock = 1;
  277.         }
  278.     } else {
  279.         badBlock = 1;
  280.     }
  281.     if (badBlock) {
  282.         (void) Disk_BadBlockRead(partFID, domainPtr, blockNum,
  283.                      (Address) block);
  284.     }
  285.     bcopy((Address) modElemPtr->fdPtr, (Address) &block[offset],
  286.           sizeof(Fsdm_FileDescriptor));
  287.     if (Disk_BlockWrite(partFID, domainPtr, blockNum, 1,
  288.                (Address) block) < 0) {
  289.         OutputPerror("WriteFileDesc: Write failed");
  290.         exit(EXIT_WRITE_FAILURE);
  291.     }
  292.     }
  293. }
  294.  
  295.  
  296. /*
  297.  *----------------------------------------------------------------------
  298.  *
  299.  * WriteSummaryInfo --
  300.  *
  301.  *    Update summary information on disk.
  302.  *
  303.  * Results:
  304.  *    None.
  305.  *
  306.  * Side effects:
  307.  *    None.
  308.  *
  309.  *----------------------------------------------------------------------
  310.  */
  311. void
  312. WriteSummaryInfo(partFID, diskInfoPtr, domainPtr, numKblocks, numFiles)
  313.     int            partFID;    /* Handle on raw disk */
  314.     Disk_Info        *diskInfoPtr;    /* Information from the super block */
  315.     Fsdm_DomainHeader    *domainPtr;    /* Reference to domain header to
  316.                      * fill in */
  317.     int            numKblocks;    /* Number of 1 Kbyte blocks. */
  318.     int            numFiles;    /* Number of files. */
  319. {
  320.     char        buffer[DEV_BYTES_PER_SECTOR];
  321.     Fsdm_SummaryInfo    *summaryInfoPtr;
  322.  
  323.     if (Disk_SectorRead(partFID, diskInfoPtr->summarySector, 1, buffer) < 0) {
  324.     OutputPerror("WriteSummaryInfo: Read failed");
  325.     exit(EXIT_READ_FAILURE);
  326.     }
  327.     summaryInfoPtr = (Fsdm_SummaryInfo *) buffer;
  328.     summaryInfoPtr->numFreeFileDesc = domainPtr->numFileDesc - numFiles -
  329.         numBadDesc;
  330.     summaryInfoPtr->numFreeKbytes = 
  331.         domainPtr->dataBlocks * FS_FRAGMENTS_PER_BLOCK - numKblocks;
  332.     if (clearDomainNumber) {
  333.     Output(stderr,"Clearing domain number field.\n");
  334.     summaryInfoPtr->domainNumber = -1;
  335.     }
  336.     summaryInfoPtr->flags = 0;
  337.     summaryInfoPtr->fixCount = fixCount;
  338.     if (Disk_SectorWrite(partFID, diskInfoPtr->summarySector, 1, buffer) < 0) {
  339.     OutputPerror("WriteSummaryInfo: Write failed");
  340.     exit(EXIT_WRITE_FAILURE);
  341.     }
  342.  
  343. }
  344.  
  345.  
  346. /*
  347.  *----------------------------------------------------------------------
  348.  *
  349.  * RecoveryCheck --
  350.  *
  351.  *    See if the disk was successfully synced. Print out information
  352.  *    from summary sector.
  353.  *
  354.  * Results:
  355.  *    Return 1 if the disk not safely synced.
  356.  *
  357.  * Side effects:
  358.  *    fixCount is set to the value in the summary sector.
  359.  *
  360.  *----------------------------------------------------------------------
  361.  */
  362. int
  363. RecoveryCheck(partFID, diskInfoPtr)
  364.     int            partFID;    /* Handle on raw disk */
  365.     Disk_Info        *diskInfoPtr;    /* Information from the super block */
  366. {
  367.     char            buffer[DEV_BYTES_PER_SECTOR];
  368.     Fsdm_SummaryInfo        *summaryInfoPtr;
  369.  
  370.     if (Disk_SectorRead(partFID, diskInfoPtr->summarySector, 1, buffer) < 0) {
  371.     OutputPerror("RecoveryCheck: Summary sector read failed");
  372.     exit(EXIT_READ_FAILURE);
  373.     }
  374.     summaryInfoPtr = (Fsdm_SummaryInfo *)buffer;
  375.     fixCount = summaryInfoPtr->fixCount;
  376.     if (verbose) {
  377.     Output(stderr, "Summary Sector Info:\n");
  378.     Output(stderr, "%s domain %d %s\n", summaryInfoPtr->domainPrefix,
  379.            summaryInfoPtr->domainNumber, 
  380.            (summaryInfoPtr->flags & FSDM_DOMAIN_NOT_SAFE) ? "not-safe" : 
  381.            "safe");
  382.         if (summaryInfoPtr->flags & FSDM_DOMAIN_TIMES_VALID) {
  383.         Output(stderr, "Down %d seconds.\n",summaryInfoPtr->attachSeconds -
  384.            summaryInfoPtr->detachSeconds);
  385.         } else {
  386.         Output(stderr, "Attach/Detach fields not valid.\n");
  387.     }
  388.     Output(stderr, "Fscheck has fixed disk %d times already.\n", fixCount);
  389.     }
  390.     if (clearFixCount) {
  391.     if (!silent) {
  392.         Output(stderr, "Fix count being reset to 0.\n");
  393.     }
  394.     fixCount = 0;
  395.     }
  396.     return(summaryInfoPtr->flags & FSDM_DOMAIN_NOT_SAFE);
  397. }
  398.  
  399.  
  400.  
  401. /*
  402.  *----------------------------------------------------------------------
  403.  *
  404.  * CheckFDBitmap --
  405.  *
  406.  *    Scan through the file descriptors and determine if all file 
  407.  *    descriptors marked as allocated and free in the bit map are
  408.  *    really that way.
  409.  *
  410.  * Results:
  411.  *    None.
  412.  *
  413.  * Side effects:
  414.  *    None.
  415.  *
  416.  *----------------------------------------------------------------------
  417.  */
  418.  
  419. void
  420. CheckFDBitmap(domainPtr, fdNum, block, bitmapPtrPtr)
  421.     register    Fsdm_DomainHeader     *domainPtr;        /* Domain to check. */
  422.     int                 fdNum;            /* File descriptor to
  423.                              * check. */
  424.     Address             block;            /* Disk block that
  425.                              * FD is in. */
  426.     register    unsigned char      **bitmapPtrPtr;    /* Ptr to FD bitmap
  427.                              * entry for fdNum. */
  428. {
  429.     int                i, j;
  430.     register unsigned char     *bitmaskPtr;
  431.     int                   allocated;
  432.     Fsdm_FileDescriptor        *fdPtr;
  433.  
  434.     for (i = 0; 
  435.      i < FSDM_FILE_DESC_PER_BLOCK / BITS_PER_BYTE && 
  436.         fdNum < domainPtr->numFileDesc;
  437.      i++, (*bitmapPtrPtr)++){
  438.     for (j = 0, bitmaskPtr = bitmasks; 
  439.          j < BITS_PER_BYTE && fdNum < domainPtr->numFileDesc; 
  440.          j++, fdNum++, bitmaskPtr++) {
  441.  
  442.         fdPtr = (Fsdm_FileDescriptor *)&block[(i * BITS_PER_BYTE + j) * FSDM_MAX_FILE_DESC_SIZE];
  443.         allocated = **bitmapPtrPtr & *bitmaskPtr;
  444.         if (allocated && (fdPtr->flags & FSDM_FD_FREE)) {
  445.         if (bitmapVerbose) {
  446.             Output(stderr,
  447.        "Free file descriptor %d allocated in bitmap.  Bitmap corrected.\n",
  448.                    fdNum);
  449.         }
  450.         foundError = 1;
  451.         fdBitmapError = 1;
  452.         **bitmapPtrPtr &= ~*bitmaskPtr;
  453.         } else if (!allocated && !(fdPtr->flags & FSDM_FD_FREE)) {
  454.         if (bitmapVerbose) {
  455.             Output(stderr,
  456.        "Allocated file descriptor %d free in bitmap.  Bitmap corrected.\n",
  457.                    fdNum);
  458.         }
  459.         foundError = 1;
  460.         fdBitmapError = 1;
  461.         **bitmapPtrPtr |= *bitmaskPtr;
  462.         }
  463.     }
  464.     }
  465. }
  466.  
  467.  
  468. /*
  469.  *----------------------------------------------------------------------
  470.  *
  471.  * SetBadDescBitmap --
  472.  *
  473.  *    Go through the bitmaps and flag all the bits for this block as
  474.  *    allocated.
  475.  *
  476.  * Results:
  477.  *    None.
  478.  *
  479.  * Side effects:
  480.  *    None.
  481.  *
  482.  *----------------------------------------------------------------------
  483.  */
  484. void
  485. SetBadDescBitmap(domainPtr, fdNum, bitmapPtrPtr)
  486.     register    Fsdm_DomainHeader     *domainPtr;        /* Domain to fix. */
  487.     int                 fdNum;            /* Bad file desc. */
  488.     register    unsigned char      **bitmapPtrPtr;    /* Ptr to bitmap entry
  489.                              * for bad file desc.*/
  490. {
  491.     int                i, j;
  492.     register unsigned char     *bitmaskPtr;
  493.  
  494.     for (i = 0; i < FSDM_FILE_DESC_PER_BLOCK / BITS_PER_BYTE && 
  495.         fdNum < domainPtr->numFileDesc;
  496.          i++, (*bitmapPtrPtr)++){
  497.     for (j = 0, bitmaskPtr = bitmasks; 
  498.          j < BITS_PER_BYTE && fdNum < domainPtr->numFileDesc; 
  499.          j++, fdNum++, bitmaskPtr++) {
  500.  
  501.          **bitmapPtrPtr |= *bitmaskPtr;
  502.      }
  503.     }
  504. }
  505.  
  506. /*
  507.  *----------------------------------------------------------------------
  508.  *
  509.  * MarkBitmap --
  510.  *
  511.  *    Mark the bits in the bit map.
  512.  *    update the cylinder map to reflect which blocks are allocated.
  513.  *
  514.  * Results:
  515.  *    -1 if couldn't mark the bitmap, 0 otherwise.
  516.  *
  517.  * Side effects:
  518.  *    None.
  519.  *
  520.  *----------------------------------------------------------------------
  521.  */
  522. int
  523. MarkBitmap(fdNum, blockNum, bitmapPtr, numFrags, domainPtr)
  524.     int          fdNum;
  525.     int          blockNum;
  526.     unsigned char *bitmapPtr;
  527.     int          numFrags;
  528.     Fsdm_DomainHeader  *domainPtr;
  529. {
  530.     register    unsigned char     *bytePtr;
  531.     register    unsigned char     *bitmaskPtr;
  532.     unsigned     char              bitmask;
  533.     int                i;
  534.     int                fullBlockNum;
  535.     int                fragOffset;
  536.     int                dupBlocks;
  537.  
  538.     if (blockNum >= num1KBlocks || blockNum < 0) {
  539.     if (verbose || lastErrorFD != fdNum) {
  540.         Output(stderr, "Block pointer %d invalid in file %d\n", 
  541.                blockNum, fdNum);
  542.         lastErrorFD = fdNum;
  543.     }
  544.     foundError = 1;
  545.     return(-1);
  546.     }
  547.     bitmask = 0;
  548.     fullBlockNum = blockNum / FS_FRAGMENTS_PER_BLOCK;
  549.     bytePtr = GetBitmapPtr(domainPtr, bitmapPtr, fullBlockNum);
  550.     fragOffset = blockNum & 0x3;
  551.     if ((fullBlockNum % domainPtr->geometry.blocksPerCylinder) & 0x1) {
  552.     fragOffset += 4;
  553.     }
  554.     bitmaskPtr = &bitmasks[fragOffset];
  555.  
  556.     dupBlocks = 0;
  557.     for (i = 0; i < numFrags; i++, bitmaskPtr++) {
  558.     if (*bitmaskPtr & *bytePtr || 
  559.         (fdNum != FSDM_ROOT_FILE_NUMBER) && blockNum == 0) { 
  560.         if (noCopy) {
  561.         if (verbose || lastErrorFD != fdNum) {
  562.             Output(stderr,
  563.     "File %d references previously allocated block.  Block %d deleted.\n", 
  564.                fdNum, blockNum + i);
  565.             lastErrorFD = fdNum;
  566.         }
  567.         foundError = 1;
  568.         return -1;
  569.         }
  570.         dupBlocks++;
  571.     }
  572.     bitmask |= *bitmaskPtr;
  573.     }
  574.     if (dupBlocks > 0) {
  575.     foundError = 1;
  576.     /*
  577.      * All fragments are duplicates, so mark bitmap and return 1 so that
  578.      * these fragments are copied.
  579.      */
  580.     if (verbose || lastErrorFD != fdNum) {
  581.         Output(stderr,"File %d contains duplicate block %d.\n",fdNum,
  582.            blockNum);
  583.     }
  584.     *bytePtr |= bitmask;
  585.     return(1);
  586.     }
  587.     *bytePtr |= bitmask;
  588.     return(0);
  589. }
  590.  
  591. /*
  592.  *----------------------------------------------------------------------
  593.  *
  594.  * Output ---
  595.  *    
  596.  *    Prints the output to the given stream, and if the outputFile is  
  597.  *    not NULL it is also printed to the outputFile.
  598.  *    
  599.  * Results:
  600.  *    None.
  601.  *
  602.  * Side effects:
  603.  *    Stuff gets printed on the given stream and the output stream.
  604.  *
  605.  *----------------------------------------------------------------------
  606.  */
  607.  
  608. #ifndef lint
  609.  
  610. int
  611. Output(va_alist)
  612.     va_dcl            /* FILE *stream, then char *format, then any
  613.                  * number of additional
  614.                  * values to be printed as described by                         * format. */
  615. {
  616.     FILE *stream;
  617.     char *format;
  618.     va_list args;
  619.     static bufferFull = FALSE;
  620.     extern char *deviceName;
  621.     extern char *partName;
  622.     int    status;
  623.  
  624.     va_start(args);
  625.     stream = va_arg(args, FILE *);
  626.     format = va_arg(args, char *);
  627.     if ((!bufferFull) && (outputFile != NULL)) {
  628.     if (fprintf(outputFile, "%s%s: ", deviceName, partName) == -1) {
  629.         bufferFull = TRUE;
  630.     }
  631.     if (bufferFull != TRUE) {
  632.         if (vfprintf(outputFile, format, args) == -1) {
  633.         bufferFull = TRUE;
  634.         }
  635.     }
  636.     }
  637.     status = fprintf(stream, "%s%s: ", deviceName, partName);
  638.     if (status != -1) {
  639.     status = vfprintf(stream, format, args);
  640.     }
  641.     return status;
  642. }
  643. #else
  644. /* VARARGS1 */
  645. /* ARGSUSED */
  646. int
  647. Output(stream,format)
  648.     FILE *stream;
  649.     char *format;
  650. {
  651.     return 0;
  652. }
  653. #endif lint
  654.  
  655.  
  656. /* 
  657.  *----------------------------------------------------------------------
  658.  *
  659.  * OutputPerror --
  660.  *
  661.  *    Prints the given message on stderr and the outputFile stream 
  662.  *    using the same format as OutputPerror().
  663.  *
  664.  * Results:
  665.  *    None.
  666.  *
  667.  * Side effects:
  668.  *    Stuff gets printed.
  669.  *
  670.  *----------------------------------------------------------------------
  671.  */
  672.  
  673. #ifndef lint
  674. void
  675. OutputPerror(va_alist)
  676.     va_dcl            /* char *format, then any
  677.                  * number of additional
  678.                  * values to be printed as described by                         * format. */
  679. {
  680.     char *format;
  681.     va_list args;
  682.  
  683.     va_start(args);
  684.     format = va_arg(args, char *);
  685.     if ((format != 0) && (*format != 0)) {
  686.     Output(stderr, format, args);
  687.     }
  688.     if ((errno < 0) || (errno >= sys_nerr)) {
  689.     return;
  690.     }
  691.     Output(stderr, "%s\n", sys_errlist[errno]);
  692. }
  693.  
  694. #else
  695. /* VARARGS1 */
  696. /* ARGSUSED */
  697. void 
  698. OutputPerror(msg)
  699.     char *msg;        
  700. {
  701. }
  702. #endif
  703.  
  704.  
  705.  
  706. /*
  707.  *----------------------------------------------------------------------
  708.  *
  709.  * WriteOutputFile ---
  710.  *    
  711.  *    This procedure is invoked when the outputFile stream buffer is full.
  712.  *      All we do here is set the status on the stream to -1, to indicate
  713.  *      that the buffer is full. The buffer is actually written out when the
  714.  *    stream is closed.
  715.  *    
  716.  * Results:
  717.  *    None.
  718.  *
  719.  * Side effects:
  720.  *    Status in FILE is set to -1.
  721.  *
  722.  *----------------------------------------------------------------------
  723.  */
  724.  
  725. /*ARGSUSED*/
  726. void
  727. WriteOutputFile(stream,flush)
  728.     FILE *stream;        /* pointer to outputFile */
  729.     int flush;             /* ignore this */
  730. {
  731.     if (!silent && stream->status != -1 && 
  732.         stream->lastAccess + 1 - stream->buffer == stream->bufSize) {
  733.     fprintf(stderr,">>Output buffer overflow. %s\n",
  734.             "Subsequent output will not appear in output file.");
  735.     }
  736.     stream->status = -1;
  737. }
  738.  
  739.  
  740. /*
  741.  *----------------------------------------------------------------------
  742.  *
  743.  * CloseOutputFile ---
  744.  *
  745.  *     Flushes the buffer to disk. 
  746.  *    
  747.  * Results:
  748.  *    None.
  749.  *
  750.  * Side effects:
  751.  *    None.
  752.  *
  753.  *----------------------------------------------------------------------
  754.  */
  755.  
  756. int
  757. CloseOutputFile(stream)
  758.     FILE *stream;        /* pointer to outputFile */
  759. {
  760.     Fsdm_FileDescriptor *fdPtr;
  761.     static u_char fdBlock[FS_BLOCK_SIZE];
  762.     static u_char buffer[FS_BLOCK_SIZE];
  763.     static u_char tempBuffer[10];
  764.     int         bytesToWrite;
  765.     int            bytesWritten;
  766.     int            blockNum;
  767.     int            offset;
  768.     int            startBlock;
  769.     int            startByte;
  770.     int            i;
  771.     int            bytesUsed;
  772.     int            bytesDone;
  773.  
  774.  
  775.     if (!writeDisk) {
  776.     return;
  777.     }
  778.     if (outputFileNum == -1) {
  779.     Output(stderr,
  780.         "File %s does not exist in root directory. %s\n",
  781.         outputFileName,
  782.         "Unable to write output to disk.");
  783.         return;
  784.     }
  785.     blockNum = domainPtr->fileDescOffset + 
  786.            outputFileNum / FSDM_FILE_DESC_PER_BLOCK;
  787.     offset = (outputFileNum & (FSDM_FILE_DESC_PER_BLOCK - 1)) * 
  788.           FSDM_MAX_FILE_DESC_SIZE;
  789.     if (debug) {
  790.     Output(stderr,"Output file number is %d.\n", outputFileNum);
  791.     }
  792.     if (Disk_BlockRead(partFID, domainPtr, blockNum, 1, 
  793.                (Address) fdBlock) < 0) {
  794.     OutputPerror("Unable to read output fd.");
  795.     return;
  796.     }
  797.     fdPtr = (Fsdm_FileDescriptor *) &fdBlock[offset];
  798.     if (fdPtr->direct[0] != FSDM_NIL_INDEX) {
  799.     if (Disk_BlockRead(partFID, domainPtr,
  800.               VirtToPhys(domainPtr, fdPtr->direct[0]) /
  801.               FS_FRAGMENTS_PER_BLOCK, 1,
  802.               (Address) buffer) < 0) {
  803.         Output(stderr,"Can't read output file.");
  804.         return;
  805.     }
  806.     if (sscanf(buffer," %d",&bytesUsed) != 1) {
  807.         bytesUsed = 0;
  808.     }
  809.     } else {
  810.     bytesUsed = 0;
  811.     }
  812.     if (fdPtr->lastByte + 1 - bytesUsed  < 
  813.     stream->bufSize - stream->writeCount) {
  814.     Output(stderr,
  815.         "Output file %s is not big enough for all the output, %d > %d\n",
  816.            outputFileName, stream->bufSize - stream->writeCount, 
  817.            fdPtr->lastByte + 1 - bytesUsed);
  818.     bytesToWrite = fdPtr->lastByte + 1 - bytesUsed;
  819.     } else {
  820.     bytesToWrite = stream->bufSize - stream->writeCount;
  821.     }
  822.     if (bytesUsed + bytesToWrite > FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE) {
  823.     Output(stderr,"Output exceeds direct blocks in file.\n");
  824.     bytesToWrite = FSDM_NUM_DIRECT_BLOCKS * FS_BLOCK_SIZE - bytesUsed;
  825.     }
  826.     if (debug) {
  827.     Output(stderr,"There are %d bytes of output to be written.\n",
  828.            bytesToWrite);
  829.     }
  830.     startBlock = bytesUsed / FS_BLOCK_SIZE;
  831.     startByte = bytesUsed - startBlock * FS_BLOCK_SIZE;
  832.     bytesDone = bytesUsed;
  833.  
  834.     for (i = startBlock, bytesWritten = 0; 
  835.      bytesDone <= fdPtr->lastByte && 
  836.      i < FSDM_NUM_DIRECT_BLOCKS; 
  837.      i++) {
  838.     if (fdPtr->direct[i] == FSDM_NIL_INDEX) {
  839.         Output(stderr,"Output file has a hole -- you lose.\n");
  840.         continue;
  841.     }
  842.     if (debug) {
  843.         Output(stderr,"Writing to block %d.\n",fdPtr->direct[i]);
  844.     }
  845.     if (startByte > 0 || 
  846.         bytesToWrite - bytesWritten < FS_BLOCK_SIZE - startByte) {
  847.         int numBytes;
  848.         int bytesToZero;
  849.  
  850.         numBytes = min(bytesToWrite - bytesWritten,
  851.                FS_BLOCK_SIZE - startByte);
  852.         if (Disk_BlockRead(partFID, domainPtr,
  853.               VirtToPhys(domainPtr, fdPtr->direct[i]) /
  854.               FS_FRAGMENTS_PER_BLOCK, 1,
  855.               (Address) buffer) < 0) {
  856.         Output(stderr,"Can't read output file.");
  857.         return;
  858.         }
  859.         bcopy((Address) &stream->buffer[bytesWritten],
  860.           (Address) &buffer[startByte], numBytes);
  861.         bytesToZero = min(fdPtr->lastByte + 1 - bytesDone - numBytes,
  862.                   FS_BLOCK_SIZE - startByte - numBytes);
  863.         bzero((Address) &buffer[startByte + numBytes], bytesToZero);
  864.         if (Disk_BlockWrite(partFID, domainPtr, 
  865.                    VirtToPhys(domainPtr,fdPtr->direct[i]) / 
  866.                    FS_FRAGMENTS_PER_BLOCK, 1, buffer)  < 0) {
  867.         OutputPerror("Unable to write to output file");
  868.         return;
  869.         }
  870.         bytesWritten += numBytes;
  871.         bytesDone += numBytes + bytesToZero;
  872.         startByte = 0;
  873.     } else {
  874.         if (Disk_BlockWrite(partFID, domainPtr, 
  875.                    VirtToPhys(domainPtr,fdPtr->direct[i]) / 
  876.                    FS_FRAGMENTS_PER_BLOCK, 1, 
  877.                    (Address) &stream->buffer[bytesWritten]) < 0) {
  878.         OutputPerror("Unable to write to output file");
  879.         return;
  880.         }
  881.         bytesWritten += FS_BLOCK_SIZE;
  882.         bytesDone += FS_BLOCK_SIZE;
  883.     }
  884.     }
  885.     if (fdPtr->direct[0] != FSDM_NIL_INDEX) {
  886.     if (Disk_BlockRead(partFID, domainPtr,
  887.               VirtToPhys(domainPtr, fdPtr->direct[0]) /
  888.               FS_FRAGMENTS_PER_BLOCK, 1,
  889.               (Address) buffer) < 0) {
  890.         Output(stderr,"Can't read output file.");
  891.         return;
  892.     }
  893.     sprintf(tempBuffer,"%05d",bytesWritten + bytesUsed);
  894.     bcopy(tempBuffer, buffer, 5);
  895.     if (Disk_BlockWrite(partFID, domainPtr,
  896.               VirtToPhys(domainPtr, fdPtr->direct[0]) /
  897.               FS_FRAGMENTS_PER_BLOCK, 1,
  898.               (Address) buffer) < 0) {
  899.         Output(stderr,"Can't write output file.");
  900.         return;
  901.     }
  902.     }
  903. }
  904.  
  905.  
  906. /*
  907.  *----------------------------------------------------------------------
  908.  *
  909.  * ExitHandler ---
  910.  *
  911.  *     Called when program exits. Flushes output stream.
  912.  *    
  913.  * Results:
  914.  *    None.
  915.  *
  916.  * Side effects:
  917.  *    None.
  918.  *
  919.  *----------------------------------------------------------------------
  920.  */
  921.  
  922. void
  923. ExitHandler()
  924. {
  925.     if (outputFile != NULL && rootPart) {
  926.     CloseOutputFile(outputFile);
  927.     }
  928. }
  929.  
  930. /*
  931.  *----------------------------------------------------------------------
  932.  *
  933.  * ClearFd ---
  934.  *
  935.  *     Clears the contents of the fd.
  936.  *    
  937.  * Results:
  938.  *    None.
  939.  *
  940.  * Side effects:
  941.  *    None.
  942.  *
  943.  *----------------------------------------------------------------------
  944.  */
  945.  
  946. void
  947. ClearFd(flags, fdPtr)
  948.     int    flags;                /* File descriptor flags */ 
  949.     Fsdm_FileDescriptor *fdPtr;        /* File descriptor to be cleared */
  950. {
  951.     int index;
  952.  
  953.     fdPtr->magic = FSDM_FD_MAGIC;
  954.     fdPtr->flags = flags;
  955.     fdPtr->firstByte = -1;
  956.     fdPtr->lastByte = -1;
  957.     fdPtr->numKbytes = 0;
  958.     fdPtr->fileType = FS_FILE;
  959.     fdPtr->uid = 0;
  960.     fdPtr->gid = 0;
  961.     fdPtr->numLinks = 0;
  962.     for (index = 0; index < FSDM_NUM_DIRECT_BLOCKS ; index++) {
  963.     fdPtr->direct[index] = FSDM_NIL_INDEX;
  964.     }
  965.     for (index = 0; index < FSDM_NUM_INDIRECT_BLOCKS ; index++) {
  966.     fdPtr->indirect[index] = FSDM_NIL_INDEX;
  967.     }
  968. }
  969.  
  970. /*
  971.  * A table indexed by a 4 bit value is used by the allocation routine to 
  972.  * quickly determine the location of 1, 2, and 3K fragments in a byte.  
  973.  * The indices of the fragments start from 0.  If there is no such fragment in 
  974.  * the byte then a -1 is used.
  975.  */
  976.  
  977. static int fragTable[16][3] = {
  978. /* 0000 */ {-1, -1, -1},
  979. /* 0001 */ {-1, -1, 0},
  980. /* 0010 */ {3, 0, -1},
  981. /* 0011 */ {-1, 0, -1},
  982. /* 0100 */ {0, 2, -1},
  983. /* 0101 */ {0, -1, -1},
  984. /* 0110 */ {0, -1, -1},
  985. /* 0111 */ {0, -1, -1},
  986. /* 1000 */ {-1, -1, 1},
  987. /* 1001 */ {-1, 1, -1},
  988. /* 1010 */ {1, -1, -1},
  989. /* 1011 */ {1, -1, -1},
  990. /* 1100 */ {-1, 2, -1},
  991. /* 1101 */ {2, -1, -1},
  992. /* 1110 */ {3, -1, -1},
  993. /* 1111 */ {-1, -1, -1}
  994. };
  995. /*
  996.  * Macros to get to the 4-bit fragment masks of the two 4K blocks that are 
  997.  * stored in a byte.
  998.  */
  999.  
  1000. #define    UpperBlockFree(byte)    (((byte) & 0xf0) == 0x00)
  1001. #define    LowerBlockFree(byte)    (((byte) & 0x0f) == 0x00)
  1002. #define    BothBlocksFree(byte)    (((byte) & 0xff) == 0x00)
  1003. #define    GetUpperFragMask(byte) (((byte) >> 4) & 0x0f)
  1004. #define    GetLowerFragMask(byte) ((byte) & 0x0f)
  1005.  
  1006. /*
  1007.  *----------------------------------------------------------------------
  1008.  *
  1009.  * AllocBlock --
  1010.  *
  1011.  *    Allocates free fragments.
  1012.  *
  1013.  * Results:
  1014.  *    -1 if a free block cannot be found, 
  1015.  *    the virtual block number of the free block otherwise
  1016.  *
  1017.  * Side effects:
  1018.  *    Marks the fragments as allocated in the bitmap
  1019.  *
  1020.  *----------------------------------------------------------------------
  1021.  */
  1022.  
  1023. int
  1024. AllocBlock(domainPtr, fragments, blockBitmapPtr)
  1025.     Fsdm_DomainHeader     *domainPtr;         /* Ptr at domain info */
  1026.     int            fragments;        /* Number of fragments needed */
  1027.     u_char        *blockBitmapPtr;    /* Cylinder data block bitmap */
  1028. {
  1029.     int     mask;
  1030.     int     i;
  1031.     int        j;
  1032.     int     blocksPerCylinder;
  1033.     int        bitmapBytes;
  1034.     int     offset;
  1035.     int        fragSize;
  1036.     u_char    *bitmapPtr;
  1037.  
  1038.     if (fragments < 1 || fragments > FS_FRAGMENTS_PER_BLOCK) {
  1039.     Output(stderr,"Internal error: call to AllocBlock w/ fragments = %d\n",
  1040.            fragments);
  1041.         exit(EXIT_HARD_ERROR);
  1042.     }
  1043.     blocksPerCylinder = domainPtr->geometry.blocksPerCylinder;
  1044.     bitmapBytes = (unsigned int) (blocksPerCylinder + 1) / 2;
  1045.     mask = ((1 << fragments) - 1);
  1046.     fragSize = fragments;
  1047.  
  1048.     /*
  1049.      * Look for fragment of correct size, then size +1, size +2, etc.
  1050.      */
  1051.     while (fragSize <= FS_FRAGMENTS_PER_BLOCK) {
  1052.     for (i = 0, bitmapPtr = blockBitmapPtr; 
  1053.          i < domainPtr->dataCylinders; 
  1054.          i++) {
  1055.  
  1056.         for (j = 0; j < bitmapBytes; j++, bitmapPtr++) {
  1057.         /*
  1058.          * Block 0 belongs to the root directory so don't allocate it 
  1059.          * even if it is free.
  1060.          */
  1061.         if (j + i != 0) {
  1062.             if (fragSize == 4) {
  1063.             if (UpperBlockFree(*bitmapPtr)) {
  1064.                 mask <<= FS_FRAGMENTS_PER_BLOCK - fragments;
  1065.                 *bitmapPtr |= mask << 4;
  1066.                 return (i * blocksPerCylinder + j * 2) * 
  1067.                     FS_FRAGMENTS_PER_BLOCK; 
  1068.             }
  1069.             } else {
  1070.             offset = 
  1071.                 fragTable[GetUpperFragMask(*bitmapPtr)][fragSize-1];
  1072.             if (offset > -1) {
  1073.                 mask <<= FS_FRAGMENTS_PER_BLOCK - offset - 
  1074.                      fragments;
  1075.                 *bitmapPtr |= mask << 4;
  1076.                 return (i * blocksPerCylinder + j * 2) * 
  1077.                     FS_FRAGMENTS_PER_BLOCK + offset; 
  1078.             }
  1079.             }
  1080.         }
  1081.         /*
  1082.          * There may be an odd number of blocks per cylinder.  If so
  1083.          * and are at the end of the bit map for this cylinder, then
  1084.          * we can bail out now.
  1085.          */
  1086.     
  1087.         if (j == (bitmapBytes - 1) && (blocksPerCylinder & 0x1)) {
  1088.             continue;
  1089.         }
  1090.         if (fragSize == 4) {
  1091.             if (LowerBlockFree(*bitmapPtr)) {
  1092.             mask <<= FS_FRAGMENTS_PER_BLOCK - fragments;
  1093.             *bitmapPtr |= mask;
  1094.             return (i * blocksPerCylinder + j * 2 + 1) * 
  1095.                 FS_FRAGMENTS_PER_BLOCK; 
  1096.             }
  1097.         } else {
  1098.             offset = 
  1099.             fragTable[GetLowerFragMask(*bitmapPtr)][fragSize-1];
  1100.             if (offset > -1) {
  1101.             mask <<= FS_FRAGMENTS_PER_BLOCK - offset - fragments;
  1102.             *bitmapPtr |= mask;
  1103.             return (i * blocksPerCylinder + j * 2 + 1) * 
  1104.                 FS_FRAGMENTS_PER_BLOCK + offset; 
  1105.             }
  1106.         }
  1107.         }
  1108.     }
  1109.     fragSize++;
  1110.     }
  1111.     /*
  1112.      * Disk is full
  1113.      */
  1114.     return -1;
  1115. }
  1116.  
  1117.  
  1118. /*
  1119.  *----------------------------------------------------------------------
  1120.  *
  1121.  * AddToCopyList --
  1122.  *
  1123.  *    Adds information about the block to be copied to the copy list.
  1124.  *
  1125.  * Results:
  1126.  *    None.
  1127.  *
  1128.  * Side effects:
  1129.  *    Copy list element is malloced, added to copy list.
  1130.  *
  1131.  *----------------------------------------------------------------------
  1132.  */
  1133.  
  1134. void
  1135. AddToCopyList(parentType,fdPtr, fdNum, blockNum, index, blockType,fragments,
  1136.           copyUsedPtr)
  1137.     ParentType        parentType;     /* either a fd or an indirect block */
  1138.     Fsdm_FileDescriptor    *fdPtr;        /* ptr to parent fd */
  1139.     int            fdNum;        /* number of parent fd */
  1140.     int            blockNum;    /* number of parent block */
  1141.     int            index;        /* index of pointer  in parent */
  1142.     BlockIndexType    blockType;    /* type of block being copied */
  1143.     int            fragments;    /* number of fragments to copy*/
  1144.     Boolean        *copyUsedPtr;    /* Was copy of fd used ? */
  1145. {
  1146.     CopyListElement    *copyPtr;
  1147.  
  1148.     Alloc(copyPtr,CopyListElement,1);
  1149.     if (!tooBig) {
  1150.     List_InitElement((List_Links *) copyPtr);
  1151.     copyPtr->fdPtr = fdPtr;
  1152.     copyPtr->parentType = parentType;
  1153.     if (parentType == FD) {
  1154.         copyPtr->parentNum = fdNum;
  1155.         *copyUsedPtr = TRUE;
  1156.     } else {
  1157.         copyPtr->parentNum = blockNum;
  1158.     }
  1159.     copyPtr->index = index;
  1160.     copyPtr->blockType = blockType;
  1161.     copyPtr->fragments = fragments;
  1162.     List_Insert((List_Links *) copyPtr,
  1163.             LIST_ATREAR(copyList));
  1164.     }
  1165. }
  1166.  
  1167.  
  1168.